# DOM Side-Effects

<EpicVideo url="https://www.epicreact.dev/workshops/react-hooks/intro-to-dom-side-effects" />

Often when working with React you'll need to interact with the DOM directly. You
may need to use a vanilla-js (non-framework-specific) library that needs to
interact directly with the DOM. Often to make a UI accessible you need to
consider focus management requiring you to call `.focus()` on an input.

Remember that when you do: `<div>hi</div>` that's actually syntactic sugar for a
`React.createElement` so you don't actually have access to DOM nodes in your
render method. In fact, DOM nodes aren't created at all until the
`ReactDOM.createRoot().render()` method is called. Your component's render
method is really just responsible for creating and returning React Elements and
has nothing to do with the DOM in particular.

So to get access to the DOM, you need to ask React to give you access to a
particular DOM node when it renders your component. The way this happens is
through a special prop called `ref`.

There are two ways to use the `ref` prop. A callback and the `useRef` hook.

**ref callback:**

The simplest way is to use the `ref` prop is by passing a callback:

```tsx
function MyDiv() {
	return (
		<div
			ref={(myDiv) => {
				console.log(`here's my div!`, myDiv)
				return function cleanup() {
					console.log(`my div is getting removed from the page!`, myDiv)
				}
			}}
		>
			Hey, this is my div!
		</div>
	)
}
```

This is the preferred approach.

<callout-warning>
	For backward compatibility reasons, TypeScript will tell you that myDiv can be
	a `HTMLDivElement` or `null`. So you may need to handle the `null` case
	(normally, just return early). In the future, it will never be `null`.
</callout-warning>

**ref object:**

For a more complex use case (like you need to interact with the DOM after the
initial render) you can use the `useRef` hook.

Here's a simple example of using the `ref` prop with `useRef`:

```tsx
function MyDiv() {
	const myDivRef = useRef<HTMLDivElement>(null)
	useEffect(() => {
		const myDiv = myDivRef.current
		// myDiv is the div DOM node!
		console.log(myDiv)
	}, [])
	return <div ref={myDivRef}>hi</div>
}
```

The benefit of this API over the `ref` callback approach is that you can
store the ref object in a variable and safely access it later within a
`useEffect` callback or event handlers.

After the component has been rendered, it's considered "mounted." That's when
the useEffect callback is called and so by that point, the ref should have
its `current` property set to the DOM node. So often you'll do direct DOM
interactions/manipulations in the `useEffect` callback.

Every element has a special `ref` prop (as shown above). You pass a ref to that
prop and React will give you a reference to the thing that's created for that
element.

You can also pass `ref` to a function component and that component can forward
the `ref` onto another element, or it can add handy methods onto it using
`useImperativeHandle` which we'll cover in the "Advanced React APIs" workshop.

📜 Learn more about `useRef` from the docs:
https://react.dev/reference/react/useRef

🦉 Note, sometimes the DOM interaction will make observable changes to the UI.
In those cases you'll want to use `useLayoutEffect` and we cover that in the
"Advanced React APIs" workshop.

🦉 A ref is basically state that's associated to a React component that will not
trigger a rerender when changed. So you can store whatever you'd like in a ref,
not just DOM nodes.

Keep in mind, React can't track when you change a ref value. That's part of it's
appeal in some cases and it can cause trouble in others. You'll develop the
intuition of when to use which over time, but in general it's best to start with
state if you're unsure and then move to a ref if you decide you don't want a
rerender when it's updated. We'll dive deeper into non-DOM refs in future
workshops.
